package imp.core.data.songdata;

import imp.core.basics.ErrorHandler;
import imp.core.basics.IOManager;
import imp.core.basics.date.Date;
import imp.core.data.PathData;
import imp.core.data.SessionData;
import imp.core.data.SettingsData;
import imp.core.data.configuration.FilePaths;
import imp.core.debug.DebugManager;
import imp.core.misc.SortManager;

import java.util.ArrayList;


/**
 * This class administers the entire song data, i.e. it loads and writes the songs and 
 * offers methods to get a song.
 * @author Patrick Arnold
 * @since 08.09.2010
 *
 */
public class SongData implements FilePaths {

	
	/** The list that contains the song objects. */
	private static ArrayList<Song> songs;
	
	
	/**
	 * Loads the songs from the songs.dat, creates the song objects and puts it in the
	 * songs array list.
	 * @return Specifies whether loading the song file has been successful or not.
	 */
	public static boolean loadData() {
		
		songs = new ArrayList<Song>();
		
		String path = PathData.getProgrampath() + SONGDATA;
		String[] file = IOManager.loadFile( path);
		
		if( file == null) {
			return false;
		}
		
		for( int i=0; i < file.length; i++) {
			String line = file[i];
			Song song = createSongObject( line, i+1);
			if( song == null) {
				return false;
			}
			songs.add( song);
		}
		
		
		// Sort the songs:
		songs = SortManager.sortSonglist( songs, SettingsData.getSortKey());
		
		
		// Debug Mode - Display the first 10 songs in the sorted list:
		if( SessionData.isDebugMode() && (songs.size() > 0)) {
		
			ArrayList<String> samples = new ArrayList<String>();
			
			for( int i=0; i < songs.size(); i++) {
				samples.add( songs.get(i).getTitle());
				if( i == 9) {
					break;
				}
			}
			
			int l = samples.size();
			String[] debugOutput = new String[l];
			
			for( int i=0; i < l; i++) {
				debugOutput[i] = samples.get(i);
			}
			
			DebugManager.displayStringField( debugOutput, "Sorted Song List");
			
		}
		
		
		return true;
		
	}
	
	
	
	/**
	 * Creates a song object from a line from the songs.dat.
	 * @param line A line from the song.dat ( ":: separated file").
	 * @param linenumber The line number in the songs.dat (needed for a possible error message).
	 * @return The song object or null, if there was an error.
	 */
	private static Song createSongObject( String line, int linenumber) {
	
		try {
		
    		String[] file = line.split( "::");
    		
    		for( int i=0; i < file.length; i++) {
    			file[i] = file[i].trim();
    		}
    		
    		long id = Long.parseLong( file[0]);
    		String filename = file[1];
    		String title = file[2];
    		String interpret = file[3];
    		int year = Integer.parseInt( file[4]);
    		double rating = Double.parseDouble( file[5]);
    		
    		String[] tags = file[6].split( ",");
    		for( int i=0; i < tags.length; i++) {
    			tags[i] = tags[i].toLowerCase();
    			tags[i] = tags[i].trim();
    		}
    		
    		int length = Integer.parseInt( file[7]);
    		Date registrationDate = new Date( file[8], false);
    		
    		Date lastPlayed;
    		
    		if( file[9].length() == 10) {
    			lastPlayed = new Date( file[9], false);
    		} else {
    			lastPlayed = null;
    		}
    		
    		int numberOfPlayings = Integer.parseInt( file[10]);
    		String annotation = file[11];
    		String language = file[12];
    		String category = file[13];
    		
    		StringBuffer lyrics = null;
    		
    		String path = PathData.getProgrampath() + "data//lyrics//" + id + "lyr";
    		if( IOManager.fileExists( path)) {
    			String[] myLyrics = IOManager.loadFile( path);
    			lyrics = new StringBuffer();
    			for( int i=0; i < myLyrics.length; i++) {
    				lyrics.append( myLyrics[i] + "\n");
    			}
    		}
    		
    		
    		Song mySong = new Song( id, filename, title, interpret, year, rating, tags, length, 
    				registrationDate, lastPlayed, numberOfPlayings, annotation, language, category, 
    				lyrics);
    		
    		// Display the first 3 song objects as a sample
    		if( SessionData.isDebugMode() && linenumber <= 3) {
    			DebugManager.displaySong( mySong);
    		}
    		
    		return mySong;
		
		} catch( Exception e) {
			
			String message = "Incorrect line in file songs.dat: <br /> &nbsp &nbsp &nbsp "
				+ "Line " + linenumber;
			String location = ErrorHandler.getParserLocation();
			ErrorHandler.error( message, location, e);
			return null;
			
		}
		
		
	}
	
	
	
	/**
	 * 
	 * Writes the song data.
	 * @return Specifies whether writing the song data has been successful or not.
	 */
	public static boolean writeData() {
		
		int l = songs.size();
		String[] output = new String[l];
		
		
		for( int i=0; i < l; i++) {
		
			Song song = songs.get(i); 
			String line = "";
			
			line += song.getId() + " :: "
				+ song.getFilename() + " :: "
				+ song.getTitle() + " :: "
				+ song.getInterpret() + " :: "
				+ song.getYear() + " :: "
				+ song.getRating() + " :: "
				+ song.getTagsString() + " :: "
				+ song.getLength() + " :: "
				+ song.getRegistrationDateString() + " :: "
				+ song.getLastPlayedString() + " :: "
				+ song.getNumberOfPlayings() + " :: "
				+ song.getAnnotations() + " :: "
				+ song.getLanguage() + " :: "
				+ song.getCategory() + " :: ";
				
			output[i] = line;	
			
		}
		
		
		if( SessionData.isDebugMode()) {
			
			
			ArrayList<String> lines = new ArrayList<String>();
			
			for( int i=0; i < l; i++) {
				lines.add( output[i]);
				if( i == 9) {
					break;
				}
			}
			
			l = lines.size();
			String[] debugOutput = new String[l];
			
			for( int i=0; i < l; i++) {
				debugOutput[i] = lines.get(i);
			}
			
			DebugManager.displayStringField( debugOutput, "Song Data to Write");
			
		}
		
		
		String path = PathData.getProgrampath() + SONGDATA;
		IOManager.write( output, path, false);
		
		return true;
		
	}
	
	
	
	/**
	 * Specifies whether a song exists or not (with regard to a specified id).
	 * @param id The song id.
	 * @return Specifies whether the song exists or not.
	 */
	public static boolean songExists( long id) {

		for( int i=0; i < songs.size(); i++) {
			if( id == songs.get(i).getId()) {
				return true;
			}
		}
		
		return false;
		
	}

	
	
	/**
	 * Changes the category of songs when a category was deleted.
	 * @param oldCategory The name of the old category, so the name of the category 
	 * which was deleted.
	 * @param replacement The replacement for the old category (must be an existing
	 * category).
	 */
	public static void changeCategory( String oldCategory, String replacement) {
		
		for( int i=0; i < songs.size(); i++) {
			
			Song song = songs.get(i);
			String category = song.getCategory();
			
			if( category.equals( oldCategory)) {
				song.setCategory( replacement);
				songs.set( i, song);
			}
			
		}
		
	}
	
	
}